package com.hst.capacity.facade.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.hst.capacity.domain.enums.Rep;
import com.hst.capacity.domain.model.response.DefaultVO;
import com.hst.capacity.domain.model.response.auth.LoginUser;
import com.hst.capacity.domain.service.TokenService;
import com.hst.capacity.infra.web.config.BrandTokenProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * 访问令牌身份验证过滤器
 *
 * @author hans
 */
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    /* 定义无须Token验证的URI*/
    // private static List<String> excludeURI = Arrays.asList("/auth/sign-in", "");
    // private static final AntPathRequestMatcher DEFAULT_EXCLUDE_URI_MATCHER = new AntPathRequestMatcher("/wx/official/authorization/**");

    final BrandTokenProperties tokenProperties;

    private List<AntPathRequestMatcher> defaultExcludeUriMatchers;

    public TokenAuthenticationFilter(BrandTokenProperties tokenProperties) {
        this.tokenProperties = tokenProperties;
        // 初始化 defaultExcludeUriMatchers
        this.defaultExcludeUriMatchers = new ArrayList<>();
        tokenProperties.getExcludeUris().forEach(uri -> {
            this.defaultExcludeUriMatchers.add(new AntPathRequestMatcher(uri.trim()));
        });
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //if (!excludeDecide(request)) {
            /* 请求头 - 访问Token */
            String accessToken = request.getHeader("Access-Token");
            if (StrUtil.isEmpty(accessToken)) {
                // Token不能为空
                jsonResponse(response);
                return;
            }

            if (!getService(request).verifyAccessToken(accessToken)) {
                log.debug("Token校验不通过!");
                jsonResponse(response);
                return;
            }

            /* 授权验证 */
            if (this.tokenProperties.getAuthorize()) {
                LoginUser loginUser = getService(request).getLoginUser(accessToken);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
       // }
        filterChain.doFilter(request, response);
    }

    private boolean excludeDecide(HttpServletRequest request) {
        for (AntPathRequestMatcher matcher : this.defaultExcludeUriMatchers) {
            if (matcher.matches(request))
                return true;
        }
        return false;
    }

    private TokenService getService(HttpServletRequest request) {
        ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
        return ctx.getBean(TokenService.class);
    }

    /**
     * 返回JSON报文
     */
    protected void jsonResponse(HttpServletResponse response) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.write(JSON.toJSONString(DefaultVO.error(Rep.INVALID_ACCESS_TOKEN)));
        out.flush();
        out.close();
    }

}
